package twoD.hofem.Q;

/**
 * MeshPart is the base class for all parts of the mesh.
 * 
 * <br><br><b>Direct Known Subclasses</b><br>
 * {@link MeshPartP}
 * 
 * @author <font style="background-color: black; color: white;">&nbsp;:: Team 1
 *         ::&nbsp;</font><a href="mailto:luowei.de@googlemail.com"><font
 *         style="background-color: red; color: white;">&nbsp; Luo
 *         &nbsp;</font></a><a
 *         href="mailto:enes.siljak@ruhr-uni-bochum.de"><font
 *         style="background-color: green; color: white;">&nbsp; Siljak
 *         &nbsp;</font></a><a href="mailto:engr_asifkhan@yahoo.com"><font
 *         style="background-color: blue; color: white;">&nbsp; Khan
 *         &nbsp;</font></a>
 * 
 */
public abstract class MeshPart {

	/**
	 * Returns the number of shape functions (i.e. modes) associated with this
	 * MeshPart. For instance, a node has one associated shape function.
	 * 
	 * @return number of modes
	 */
	public abstract int countModes();

	/**
	 * Returns the DOF numbers of all MeshParts associated with this MeshPart.
	 * 
	 * @return array of int arrays
	 */
	protected abstract int[][] getAllDofNumbers();
	
	private int d;
	private int[] dofNumbers;
	private int[] tArray;
	private double[] uLocal;
	
	private Constraint constraint;
	
	/**
	 * Returns the number of degrees of freedom for this MeshPart and its associated mesh parts. 
	 * The returned value depends on the number of fields of the problem 
	 * at hand <b>d</b> and the polynomial degree <b>p</b> (for edges and faces).
	 * 
	 * @return Number of degrees of freedom of this MeshPart and its associated mesh parts.
	 */
	public int countDofs(){
		return tArray.length;
		
	}
	
	/**
	 * Enumerates DOFs for this MeshPart.
	 * Argument is starting number for numbering of DOFs on this MeshPart.<br>
	 * 
	 * @return Next available number for DOFs.<br>
	 * 
	 */
	public int enumerateDofs(int idx){
		dofNumbers = new int[d*countModes()];
		
		int dofCounter = idx;
		int k;
		for(int i = 0; i < countModes(); i++){
			for(int j = 0; j < d; j++){
				k = d * i + j;
				if (constraint == null || constraint.isFree(j))
					dofNumbers[k] = dofCounter++;	
				
				else
					dofNumbers[k] = -1;
			}
		}
		
		return dofCounter;
	}
	
	/**
	 * Returns Constraint of this MeshPart
	 * 
	 * @return Constraint of this MeshPart
	 */
	public Constraint getConstraint(){
		return constraint;
	}
	
	/**
	 * Returns number of field functions.
	 * 
	 * @return Number of field functions.
	 */
	public int getD(){
		return d;
	}
	
	/**
	 * Returns array of degrees of freedom of this element.
	 * 
	 * @return Array of DOF numbers.
	 */
	public int[] getDofNumbers(){
		return dofNumbers;
	}
	
	/**
	 * Returns T-array of this MeshPart.
	 * 
	 * @return T-array of this MeshPart.
	 */
	public int[] getTArray(){
		return tArray;
	}
	
	/**
	 * Returns local solution vector <b><i>u<sub>e</sub></b></i>
	 * 
	 * @return Local solution vector.
	 */
	public double[] getULocal(){
		return uLocal;
	}
	
	/**
	 * Sets the constraint for this MeshPart. 
	 * 
	 * @param c Constraint
	 */
	public void setConstraint(Constraint c){
		constraint = c;
	}
	
	/**
	 * Sets the number of field functions.
	 * 
	 * @param d Number of field functions.
	 */
	public void setD(int d){
		this.d = d;
	}
	
	/**
	 * Selects the entries of the local solution vector <b><i>u<sub>e</sub></b></i> from 
	 * global solution vector <b><i>u</b></i> using<br>
	 * <pre>
	 * <b><i>u<sub>e</sub></b></i>[i]=| <b><i>u</b></i>[T<sub>i</sub>] if T<sub>i</sub> &#8800; -1
	 *       | 0 otherwise 
	 * </pre>
	 * 
	 * @param uGlobal Global vector solution
	 */
	public void setUGlobal(double[] uGlobal){
		uLocal = new double[tArray.length];
		
		for(int i = 0; i < uLocal.length; i++){
			if (tArray[i] != -1)
				uLocal[i] = uGlobal[tArray[i]];
			else
				uLocal[i] = 0;
		}
	}
	
	/**
	 * Sets up the T array for this MeshPart. <br><br>
	 * Degrees of freedom that are returned by <code>getAllDofNumbers()</code> are supposed to be 
	 * ordered in this way for the face, for the edge in analogy with this:<br>
	 * <code>getAllDofNumbers()[0..4][] - nodes<br>
	 * getAllDofNumbers()[5..8][] - edges<br>
	 * getAllDofNumbers()[9][] - face<br>
	 * 
	 */
	public void setUpTArray(){
		int[][] allDofs = getAllDofNumbers();
		
		int n = 0;
		for(int i = 0; i < allDofs.length; i++)
			n += allDofs[i].length;

		tArray = new int[n];
		int tCounter = 0;
		for(int i = 0; i < allDofs.length; i++)
			for(int j = 0; j < allDofs[i].length; j++){
				tArray[tCounter++] = allDofs[i][j];
			}
	}
}
